/* Copyright (c) 2001 Nextel Communications, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of Nextel Communications, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NEXTEL
 * COMMUNICATIONS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.nextel.ui; // Generated package name 
import com.nextel.ui.custom.TableEditListener;
import com.nextel.util.Debug;
import com.nextel.util.Logger;
import com.nextel.util.lwuit.Font;
import java.util.Timer;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

/**
 * <p>
 * Focusable component that displays a scrollable list of rows that can be
 * divided into columns.
 * <p><b>Example:</b><img src="doc-files/Grid.jpg">
 * <p>
 * The component supports vertical scrolling and enables the
 * scrollbar when the data populated exceeds the maximum number
 * of viewport rows.  Other features include:
 * </p>
 * <p>
 * <li>
 * The currently selected grid row is reverse-videoed while unselected rows have
 * normal video.
 * </li>
 * <li>
 * The currently selected row may be configured to render using a different than
 * the unselected items.
 * </li>
 * <li>
 * The OGrid class contains a default rendering implementation
 * ({@link com.nextel.ui.OGridRowRenderer}) used to render grid
 * rows for cell objects (Strings, int, short, Image).
 *</li>
 *<li>
 * The default {@link com.nextel.ui.OGridRowRenderer} may be configured for
 * a single OGrid instance.
 *</li>
 *<li>
 * The {@link com.nextel.ui.OGridRow} interface provides the {@link com.nextel.ui.OGridRowRenderer} with the capability
 * to allocate, deallocate, and retrieve cell object values and cell renderers for
 * a specific grid row.
 * <li> Grid Rows and Cell columns may have a specific rendering mechanism
 * configured using the {@link com.nextel.ui.OGridRow}, {@link com.nextel.ui.OGridRowRenderer},
 * {@link com.nextel.ui.OCell} and {@link com.nextel.ui.OCellRenderer} interfaces.
 * <li>The {@link com.nextel.ui.OGridInfo} has rendering attributes and contains
 * methods used to calculate X/Y coordinates based on grid and cell rendering
 * information.
 * </li>
 * </p>
 *
 * @author Anthony Paper
 */
public class OGrid extends OFocusableComponent {

    protected OGridInfo gridInfo;
    protected String label;
    protected Font labelFont;
    protected int labelWidth;
    // The height of text for the selected item.
    protected int selectedTextHeight;
    // The height of text for items which are not selected.
    protected int unselectedTextHeight;
    // The font to use for the selected item
    protected Font selectedFont;
    // The font to use for unselected items
    protected Font unselectedFont;
    // width of the scroll grid, including the scrollbar width
    protected int width;
    // width of the list in pixels, excluding the scrollbar width
    protected int listWidth;
    protected int listHeight;
    protected int columnHeadingsHeight;
    // the height of the list in pixels
//  protected int height;
    // the number of lines which can be displayed in the available space
    protected int nbrOfDisplayableLines;
    // the number of lines which are displayed in the available space; equal to or
    // less than nbrOfDisplayableLines
    protected int nbrOfDisplayedLines;
    // the index in the list of the first line displayed
    protected int topLineIndex;
    // the index in the list of the last line displayed
    protected int bottomLineIndex;
    // 0-based index of the selected displayed row.  this index is NOT an index
    // into the list of items, but is the index of the row in the scroll grid
    // display.  e.g., if 3 items can be displayed in the scroll grid window, this
    // will have a value of 0, 1, or 2
    protected int lineSelected;
    //0-based index of the selected displayed column.
    protected int columnSelected;
    //0-based index of the first column to render
    protected int basecolumn;
    // the set of items which may be displayed
    public static final int SELECTED_COLOR = OColor.TEXT_PERIMETRO_SELECTED;
//  protected Object [] items;
    OGridRow[] items;
    protected OScrollBar scrollBar;
    protected boolean firstTime = true;
    // renderer used to render the list items
    protected OGridRowRenderer itemORenderer;

    protected int screenwidth = 0;
    
    public int widthScre = 0;
    /**
     * Indicates whether the scrollbar should only draw the DOWN Arrow.
     * The default value is false and both arrows shall be displayed.
     */
    protected boolean downArrowOnlyFlag = false;
    protected TableEditListener tableListener;
    long lastTimeDeleteButtonPressed, milliSencodsToDeleteRow = 1000;
    //IDEN
    public static final short BTN_OK = -23;
    public static final short BTN_NUMERAL = 35;
    public static final short BTN_START = 42;
    protected int indchar = 0;
    protected short gc = 0;
    protected Timer timer;

    public void setDownArrowOnlyFlag(boolean flag) {
        downArrowOnlyFlag = flag;
    }
    /**
     * Default Renderer used to render grid rows and columns
     */
    protected OGridRowRenderer defaultORenderer =
            new OGridRowRenderer() {

                /**
                 * Method used to render columns based on the left X
                 * and top Y coordinates.
                 */
                public void renderCol(com.nextel.util.lwuit.Graphics g,
                        int leftX, int topY,
                        int rowNum,
                        int colNum,
                        OCell cell,
                        int cellWidth,
                        int cellAlignment,
                        OGridInfo gridInfo) {
                    if ((cell == null || cell.value == null)) {
                        return;
                    }
                    int currentSelectionIndex = topLineIndex + lineSelected;
 
                    Font font = g.getFont();
                    //
                    // Calculate X based on cell width, cell alignment,
                    // scrollbar width, and horizontal grid border width
                    //
                    int x = OGridInfo.calculateX(
                            g,
                            leftX,
                            cell.value,
                            colNum,
                            gridInfo.numberOfColumns,
                            gridInfo.getHorizontalBorderWidth(),
                            gridInfo.getScrollBarWidth(),
                            cellWidth,
                            cellAlignment);
                    //
                    // Calculate the Y based on cell height, font,
                    // and image height.  This routine only adjusts
                    // Y value based on the image height
                    //
                    int y = OGridInfo.calculateY(
                            g,
                            topY ,
                            cell.value,
                            colNum,
                            gridInfo.numberOfColumns);
                    int antcolor = g.getColor();

                    g.setColor(OGrid.SELECTED_COLOR);//selected cell color

                    if (cell.value instanceof Image) {
                        Image image = (Image) cell.value;
                        if (rowNum == lineSelected && colNum == columnSelected) {
                            g.drawRect(leftX - 2, topY - 2, cellWidth, image.getHeight());
                        }
                        g.setColor(antcolor);
                        g.drawImage(image, x, y, Graphics.TOP | cellAlignment);
                    } else {
                        String value = (cell.value instanceof String
                                ? (String) cell.value
                                : cell.value.toString());


                        if (rowNum == currentSelectionIndex && colNum == columnSelected) {
                            g.drawRect(leftX - 2, topY - 2, cellWidth, font.getHeight());
                            int tot = value.length();
                            if (!(cell instanceof OEditableCell) && value.length() > 0 && font.stringWidth(value) > cellWidth) {
                                value = value.substring(indchar++);
                                indchar %= tot;
                            }
                        }

                        while (value.length() > 0 && font.stringWidth(value) > cellWidth) {
                            value = value.substring(0, value.length() - 1);
                        }


                        g.setColor(antcolor);
                        g.drawString(value, leftX, y, Graphics.TOP | cellAlignment);
                    }
                } // render

                /**
                 * Method used to render  rows based on the left X
                 * and top Y coordinates.
                 */
                public void renderRow(com.nextel.util.lwuit.Graphics g,
                        int x, int y,
                        int rowNum,
                        int rowWidth,
                        OGridRow gridRow,
                        OGridInfo gridInfo) {
                    OCell[] cells = gridRow.getCells();
                    if (cells != null) {

                        //
                        // For the number of columns let's render it
                        // to the screen based on the column width
                        // alignment, calculated
                        int x1 = x;
                        for (int cellIndex = basecolumn; cellIndex < cells.length; cellIndex++) {
                            OCell cell = cells[cellIndex];

                            // If we should NOT use default renderer
                            if (cell.renderer != null) {
                                cell.renderer.renderCol(
                                        g, x1, y, rowNum, cellIndex,
                                        cell,
                                        gridInfo.columnWidths[cellIndex],
                                        gridInfo.columnAlignments[cellIndex],
                                        gridInfo);
                            } else {
                                renderCol(g, x1, y, rowNum, cellIndex,
                                        cell,
                                        gridInfo.columnWidths[cellIndex],
                                        gridInfo.columnAlignments[cellIndex],
                                        gridInfo);
                            }
                            x1 = x1 + gridInfo.columnWidths[cellIndex];
                        }
                    }
                }

                /**
                 * Method used to render row.  The method renders a string row or
                 * grid row based on the type of object to be rendered.  This method
                 * is designed to support OScrolledList and OGrid components.
                 */
                public void render(com.nextel.util.lwuit.Graphics g, int x, int y, int width,
                        Object item,
                        int rowNumber,
                        OGridInfo gridInfo) {
                    if (item == null) {
                        return;
                    }
                    if (item instanceof OGridRow) {
                        renderRow(g, x, y, rowNumber, width,
                                (OGridRow) item, gridInfo);
                    } else {
                        String value = (item instanceof String
                                ? (String) item
                                : item.toString());
                        g.drawString(value, x, y, Graphics.TOP | Graphics.LEFT);
                    }
                } // render
            };

    /**
     * Creates a new <code>OGrid</code> instance.
     *
     * @param gridInfo Contains grid information used to allocate the grid object.
     */
    public OGrid(OGridInfo gridInfo) {
        super();
        if (Debug.ON) {
            Logger.dev("OGrid.ctor.3 ENTERED");
        }

        // default traverseDirections for OFocusableComponent include UP and DOWN, so
        // limit to right and left only
        //setTraverseDirections(OFocusableComponent.RIGHT | OFocusableComponent.LEFT);
        setTraverseDirections(0);
        setFocusedComponentBackground(OColor.TRANSPARENT);
        setGridInfo(gridInfo);
        basecolumn = 0;
        if (Debug.ON) {
            Logger.dev("OGrid.init EXITTING");
        }
//        showNotify();

    } // OGrid

    public void setViewableWidth(int width){
        this.screenwidth = width;
    }

    /**
     * Sets the column headings and column fonts.  The width and height associated
     * with the column headings are recalculated based on the parameters.  The
     * current implementation supports a single line for each column heading.
     *
     *
     * @param columnHeadings The array of strings to be displayed for each column
     *                       cell and Null is passed for no column headings to be
     *                       displayed.
     * @param columnHeadingsFont The font used to display column headings.
     */
    public void setColumnHeadings(String[] columnHeadings,
            Font columnHeadingsFont) {
        this.columnHeadingsHeight = 0;
        if ((columnHeadings != null) && (columnHeadings.length > 0)) {
            gridInfo.columnHeadings = columnHeadings;
            gridInfo.columnHeadingsFont = columnHeadingsFont;
            this.columnHeadingsHeight =
                    columnHeadingsFont.getHeight() + OUILook.STRING_SPACER_HEIGHT;
        }
    }

    /**
     * Method used to Retrieve the <code>OGridInfo</code> instance.
     *
     * @return The grid information used to allocate and render the grid object.
     *
     */
    public OGridInfo getGridInfo() {
        return gridInfo;
    }

    /**
     * Method used to set the <code>OGridInfo</code> instance.
     *
     * @param gridInfo Contains grid information used to render the grid object.
     */
    public void setGridInfo(OGridInfo newGridInfo) {
        gridInfo = newGridInfo;
        this.width = gridInfo.maxWidth;
        this.listWidth = gridInfo.maxWidth;
        this.selectedFont = gridInfo.selectedFont;
        this.unselectedFont = gridInfo.unselectedFont;
        setColumnHeadings(gridInfo.columnHeadings, gridInfo.columnHeadingsFont);
        this.selectedTextHeight = selectedFont.getHeight();
        this.unselectedTextHeight = unselectedFont.getHeight();
        this.listHeight = (OUILook.STRING_SPACER_HEIGHT - 1) + selectedTextHeight +
                (unselectedTextHeight * (gridInfo.viewportRows - 1));

        this.nbrOfDisplayableLines = gridInfo.viewportRows;
        this.bottomLineIndex = nbrOfDisplayableLines - 1;
    }

    /**
     * Populates the grid with the items to display.
     * You might want to use this version of populate, rather than
     * {@link #populate( OGridRow [] ) populate( OGridRow[] )}, if you need to align
     * columns within your list, or if you want to display in the list things
     * other than strings, both of which you could do by supplying a custom
     * renderer.
     *
     * @param items The items to display.
     * @param renderer A renderer to use for rendering the items to the screen.
     */
    public void populate(OGridRow[] items, OGridRowRenderer renderer) {
//        if (Debug.ON) {
//            Logger.dev("OGrid.populate Object[] ENTERED");
//        }
        this.itemORenderer = renderer;
        layOut(items);
//        if (Debug.ON) {
//            Logger.dev("OGrid.populate Object[] EXITTING");
//        }
        return;
    } // populate

    /**
     * Populates the grid with a set of items.  Default Rendering information may
     * be specified in the <code>OGridInfo</code> instance.  All columns
     * <code>OCell</code> may have a specific <code>OCellRenderer</code>
     *
     * @param items The items to be displayed in the list.  The items will be
     * rendered by a default string renderer.
     */
    public void populate(OGridRow[] items) {
//        if (Debug.ON) {
//            Logger.dev("OGrid.populate String[] ENTERED");
//        }
        populate(items, defaultORenderer);
//        if (Debug.ON) {
//            Logger.dev("OGrid.populate String[] EXITTING");
//        }
    } // populate

    /**
     * Lays out the grid list display.
     *
     * @param items The items to be displayed.
     */
    protected void layOut(OGridRow[] items) {
//        if (Debug.ON) {
//            Logger.dev("OGrid.layOut ENTERED");
//        }
        this.items = items;
        nbrOfDisplayedLines = Math.min(items.length, nbrOfDisplayableLines);
        if (bottomLineIndex >= items.length) { // bottomLineIndex is leftover from previous deletion of the last row, so
            // correct it
            bottomLineIndex = items.length - 1;
            topLineIndex = bottomLineIndex - nbrOfDisplayedLines + 1;
        } else {
            bottomLineIndex = topLineIndex + nbrOfDisplayedLines - 1;
        }

        if (lineSelected > nbrOfDisplayedLines - 1) { // the number of items displayed has decreased
            lineSelected = nbrOfDisplayedLines - 1;
        }

        this.listHeight = (OUILook.STRING_SPACER_HEIGHT - 1) + selectedTextHeight +
                (unselectedTextHeight * (nbrOfDisplayedLines - 1));

        //
        // Adjust information for grid border and scrollbar widths
        //
        if (items.length > gridInfo.viewportRows) {
            gridInfo.setScrollBarWidth(12);
        }
        gridInfo.setGridBorderType(gridInfo.gridBorderType);

//        if (Debug.ON) {
//            Logger.dev("OGrid.layOut EXITTING");
//        }

        return;
    } // layOut

    /**
     * Gets the height of the scrolled grid.
     * @return Height of the scrolled grid. The height will be 0 until
     * {@link #populate populate} is called.
     */
    public int getHeight() {
//        if (Debug.ON) {
//            Logger.dev("OGrid.getHeight CALLED, returning " +
//                    columnHeadingsHeight + listHeight);
//        }
//    return this.height;
        return (columnHeadingsHeight + listHeight);
    }

    /**
     * Gets the width of the scrolled grid, including the scroll bar.
     * @return Width of the scrolled grid.
     */
    public int getWidth() {
//        if (Debug.ON) {
//            Logger.dev("OGrid.getWidth CALLED, returning " +
//                    this.width);
//        }
        return this.width;
    }
    public int getWithScreen(){
        return widthScre;
    }

    /**
     * Paints the scrolled grid on the screen.
     *
     * @param g The graphics context
     */
    public void paint(Graphics gr) {
        com.nextel.util.lwuit.Graphics g = new com.nextel.util.lwuit.Graphics(gr);
 
        firstTime= true;
        int last = g.getColor();
        g.setColor(0xFFFFFF);
        g.fillRect(0, getY(), getWidth(), selectedTextHeight * this.nbrOfDisplayableLines + columnHeadingsHeight);
        g.setColor(last);
        // width of the list portion depends upon whether a scrollbar is needed
        //this.listWidth = this.width;
        this.listWidth = widthScre + 4;
 
        if (nbrOfDisplayableLines < items.length) {
            if (firstTime) { // create scrollbar
                firstTime = false;
 
                this.scrollBar = new OScrollBar();
                this.scrollBar.setDownArrowOnlyFlag(downArrowOnlyFlag);
            }
            this.listWidth -= scrollBar.getWidth();
        }else {
            this.scrollBar = null;
        }
 
        int oldColor = g.getColor(); // save so we can restore it
 
        int x = 0;
        int y = getY();
 
     //******************************************
          widthScre = ((this.screenwidth) - 4);
 
        if (label != null) { // draw the label on the left, if their is one
            g.setFont(labelFont);
            g.drawString(label, x, y);
        }

        //
        // Let's draw the column headings
        //
        if (columnHeadingsHeight > 0) {
         
            for (int hi = basecolumn; hi < gridInfo.columnHeadings.length; hi++) {
                g.setFont(gridInfo.columnHeadingsFont);
                int myDiff = Math.abs(
                        gridInfo.columnWidths[hi] -
                        gridInfo.columnHeadingsFont.stringWidth(
                        gridInfo.columnHeadings[hi]));
                int myX = x + 1;
                if (myDiff > 2) {
                    myX = x + (myDiff / 2);
                }
                g.drawString(gridInfo.columnHeadings[hi], myX, y,
                        Graphics.TOP | Graphics.LEFT);
                x = x + gridInfo.columnWidths[hi];
            }
 
            x = 0;
            y = getY() + columnHeadingsHeight - OUILook.STRING_SPACER_HEIGHT;
        }
        // now draw the box containing the list
        int boxLeftEdge = x + labelWidth;
        int boxTopEdge = y;
 
        paintBox(gr, boxLeftEdge, y,listWidth,//listWidth
                listHeight);
 
        // prepare to draw the items in the box
        //
        // adjust y to top of where string is to be
        y += OUILook.STRING_SPACER_HEIGHT;

        int hGridCount = 0;

        // display list items in the box
        g.setColor(OUILook.TEXT_COLOR);
        for (int listIndex = topLineIndex;
                listIndex < topLineIndex + nbrOfDisplayedLines &&
                listIndex < items.length; listIndex++) {
            Font itemFont = unselectedFont;
            int foreground = OUILook.TEXT_COLOR;
            if (listIndex == (topLineIndex + lineSelected)) { // this is the selected line; reverse-video the background
                g.setColor(hasFocus() ? OColor.GRID_SELECTION : OColor.DK_GRAY);
                g.fillRect(getX(), y - 1, listWidth, selectedTextHeight);

                foreground = OColor.TRANSPARENT;
                itemFont = selectedFont;
            }


            g.setFont(itemFont);
            g.setColor(foreground);
            //
            // Get the row grid and cells to render
            // based on the current list index
            //
            itemORenderer.render(g, x + OUILook.H_GAP, y,
                    getListWidth() - OUILook.H_GAP,
                    items[listIndex], listIndex, gridInfo);

            y += itemFont.getHeight();

            //
            // If we need to draw the horizontal lines
            // and we have not already drawn all of the
            // horizontal grid lines.  The horizontal
            // line will be drawn AFTER Y is incremented
            // therefore, it is below the item.
            //
            if (((gridInfo.gridBorderType == OGridInfo.GRID_BORDER_TYPE_HORIZONTAL) ||
                    (gridInfo.gridBorderType == OGridInfo.GRID_BORDER_TYPE_BOTH)) &&
                    (hGridCount < (gridInfo.viewportRows - 1))) {
                g.setColor(OColor.GRID_SELECTION);
                g.drawLine(x, y - 1, x + getListWidth(), y - 1);
                hGridCount++;
            }
        }

        // paint the scroll bar;
//        System.out.println("scrollBar=" + scrollBar);
        if (scrollBar != null) {
            scrollBar.ancho( widthScre);
            int percentageDisplayed = (nbrOfDisplayedLines * 100) / items.length;
            int sliderStart = (topLineIndex * 100) / items.length;
            if (bottomLineIndex == items.length - 1) {
                // the end of the list is displayed, make sure scroll bar slider covers
                // full remaining area
                 sliderStart = 100 - percentageDisplayed;
            }
            
            scrollBar.paint(g, boxLeftEdge + listWidth + 1, boxTopEdge,
                    listHeight,
//                    widthScre,
                    sliderStart, percentageDisplayed);
           

             
        }
        //
        // If we need to draw the vertical lines
        //
        if (((gridInfo.gridBorderType == OGridInfo.GRID_BORDER_TYPE_VERTICAL) ||
                (gridInfo.gridBorderType == OGridInfo.GRID_BORDER_TYPE_BOTH)) &&
                (gridInfo.columnWidths != null) &&
                (gridInfo.columnWidths.length > 1)) {
            int x1 = boxLeftEdge +2;
            int x2 = 0;
            int y1 = boxTopEdge;
            int y2 = boxTopEdge + listHeight;
            for (int index = 1; index < gridInfo.columnWidths.length ; index++) {
                //x1 = x1 + gridInfo.columnWidths[index - 1];
 
                x1 = x1 + gridInfo.columnWidths[index];
                x2 = x1;
                g.setColor(OColor.GRID_SELECTION);
                g.drawLine(x1, y1, x2, y2);
            }
        }
        g.setColor(oldColor);
//        g.setFont(oldFont);
        if (Debug.ON) {
            Logger.dev("OGrid.paint EXITTING");
        }




    } // paint

    /**
     * Gets the list item that was selected
     *
     * @return The selected list item.
     */
    public Object getSelectedValue() {
        Object value = items[topLineIndex + lineSelected];
        if (Debug.ON) {
            Logger.dev("OGrid.getSelectedValue CALLED, returning " + value);
        }
        return value;
    } // getSelectedValue

    /**
     * Sets the item that is selected. If necessary the list will be scrolled so
     * that the item is displayed.
     *
     * @param value The item that is selected
     * @exception NotFoundException if the selected item does not exist
     */
    public void setSelectedValue(Object value)
            throws Exception {
        if (Debug.ON) {
            Logger.dev("OGrid.setSelectedValue ENTERED w/value=" +
                    value);
        }
        boolean found = false;
        for (int idx = 0; idx < items.length; idx++) {
            if (items[idx].equals(value)) {
                setSelectedIndex(idx);
                found = true;
                break;
            }
        }
        if (!found) {
            throw new Exception("OGrid.setSelectedValue value " +
                    value + " not found");
        }
        repaint();
        if (Debug.ON) {
            Logger.dev("OGrid.setSelectedValue EXITTING");
        }
    } // setSelectedValue

    /**
     * Sets the item that is selected. If necessary the list will be scrolled so
     * that the item is displayed.
     *
     * @param itemIndex The index, in the list of items, of the selected item.
     * @exception NotFoundException if no item with the specified index exists
     */
    public void setSelectedIndex(int itemIndex)
            throws Exception {
        if (Debug.ON) {
            Logger.dev("OGrid.setSelectedValue ENTERED " +
                    " w/itemIndex= " + itemIndex);
        }
        if (itemIndex < topLineIndex || itemIndex > bottomLineIndex) {
            lineSelected = scrollTo(itemIndex);
        } else {
            lineSelected = itemIndex - topLineIndex;
        }
        repaint();
        if (Debug.ON) {
            Logger.dev("OGrid.setSelectedValue EXITTING");
        }
    } // setSelectedIndex

    /**
     * Scroll the list to display an item.
     *
     * @param itemIndex Index of the item to scroll to
     * @return The index, within the displayed rows, of the row scrolled to.
     * e.g., if the row scrolled to is the second of 3 displayed rows, the 0-based
     * index of 1 will be returned
     * @exception NotFoundException if no item with the specified index exists
     */
    public int scrollTo(int itemIndex)
            throws Exception {
        if (Debug.ON) {
            Logger.dev("OGrid.scrollTo ENTERED w/itemIndex=" +
                    itemIndex);
        }
        if (itemIndex > items.length - 1) {
            throw new Exception("requested index " + itemIndex +
                    " but there are only " + items.length + " items");
        }
        if (itemIndex < topLineIndex || itemIndex > bottomLineIndex) {
            
            int lastIndex = items.length - 1;
            if ((lastIndex - itemIndex + 1) >= nbrOfDisplayedLines) { // place the item at the top of the scroll display
                topLineIndex = itemIndex;
            } else // not enough items including and below the desired item to place it
            { // at the top, so place item at bottom of scroll display
                topLineIndex = itemIndex - nbrOfDisplayedLines + 1;
            }
            bottomLineIndex = topLineIndex + nbrOfDisplayedLines - 1;
            repaint();
        }
        if (Debug.ON) {
            Logger.dev("OGrid.scrollTo EXITTING, returning " +
                    (itemIndex - topLineIndex));
        }
        return itemIndex - topLineIndex;
    } // scrollTo

    /**
     * Gets the index of the item that is currently selected.
     *
     * @return the index of the currently selected item
     */
    public int getSelectedIndex() {
        if (Debug.ON) {
            Logger.dev("OGrid.getSelectedIndex CALLED, returning " +
                    topLineIndex + lineSelected);
        }

        return topLineIndex + lineSelected;
    } // getSelectedIndex

    /**
     * Processes a key press while the scroll grid has focus.
     * <p>
     * If the key pressed is the up- or down- key the list will be scrolled
     * appropriately and the selected item will change.  If the currently selected
     * item is the first or last item then a beep will ensue.  Any key other than
     * the up- or down- key is ignored.
     * @param keyCode The code of the pressed key.
     *
     * UPDATED:
     * @author Victor Laguna <vlaguna@dsbmobile.com>   *
     * Right- and left- key are used to navigate between cells in the selected row
     */
    public void keyPressed(int keyCode) {

        int currentSelectionIndex = topLineIndex + lineSelected;

        if (keyCode == OAbstractScreen.DOWN_KEY) {
//            System.out.println("OAbstractScreen.DOWN_KEY");
            indchar = 0;
            if (currentSelectionIndex < items.length - 1) { // there is a row below the current selection
                if(getTableListener()!=null) getTableListener().estadoAnterior();
                if (lineSelected < (nbrOfDisplayedLines - 1)) {
                    lineSelected++;
                }
                if (++currentSelectionIndex > bottomLineIndex) { // scroll down
                    bottomLineIndex++;
                    topLineIndex++;
                }
                if(getTableListener()!=null) getTableListener().estadoActual();
                repaint();
            }
        } else if (keyCode == OAbstractScreen.UP_KEY) {
//            System.out.println("OAbstractScreen.UP_KEY");
            indchar = 0;
            if (currentSelectionIndex > 0) { // there is a row above the current selection
                if(getTableListener()!=null) getTableListener().estadoAnterior();
                if (lineSelected > 0) {
                    lineSelected--;
                }

                if (--currentSelectionIndex < topLineIndex) { // scroll up
                    topLineIndex--;
                    bottomLineIndex--;
                }
                if(getTableListener()!=null) getTableListener().estadoActual();
                repaint();
            }
        } else if (keyCode == OAbstractScreen.RIGHT_KEY) {
//            System.out.println("OAbstractScreen.RIGHT_KEY");
            indchar = 0;
            if(getTableListener()!=null) getTableListener().estadoAnterior();

            if(columnSelected<this.gridInfo.numberOfColumns-1) this.columnSelected++;
            
            if (outsideScreen(columnSelected)) {
                if(columnSelected==0) this.basecolumn =0;
                else{
                    if(basecolumn<this.gridInfo.numberOfColumns-1) this.basecolumn++;
                }
            }
            if(getTableListener()!=null) getTableListener().estadoActual();
            repaint();

        } else if (keyCode == OAbstractScreen.LEFT_KEY) {
//            System.out.println("OAbstractScreen.LEFT_KEY");
            indchar = 0;
            if(getTableListener()!=null) getTableListener().estadoAnterior();
            
            if (this.columnSelected > 0) {
                this.columnSelected--;
            }

            if(outsideScreen(columnSelected)){
                this.basecolumn = columnSelected;
            }
          
            if(getTableListener()!=null) getTableListener().estadoActual();
            repaint();
        }
//        System.out.println("basecol=" + basecolumn);
    } // keyPressed

    /**
     * Gets the width of the list portion of the scroll grid, which excludes the
     * width of the scroll bar if one is displayed.
     *
     * @return The width of the list portion.
     */
    public int getListWidth() {
        return listWidth;
    } // getListWidth

    /**
     * @return the tableListener
     */
    public TableEditListener getTableListener() {
        return tableListener;
    }

    /**
     * @param tableListener the tableListener to set
     */
    public void setTableListener(TableEditListener tableListener) {
        this.tableListener = tableListener;
    }

    public int getColumna() {
//        System.out.println("columnSelected=" + columnSelected);
        return columnSelected;
    }

    public String getValor(int columna) {
//        System.out.println("lineSelected=" + getLineSelected());
        return getValor(getLineSelected(), columna);
    }

    public void setDatosColumna(int columna, String string) {

        if (items.length <= 0) {
            return;
        }
 
        
        Object obj = items[getLineSelected()].getCells()[columna].value;
        
        

        if (obj instanceof String) {
            items[getLineSelected()].getCells()[columna].value = string;
        }

        if (obj instanceof OTextField) {
            try {
                ((OTextField) obj).setText(string);
            } catch (Exception e) {
            }
        }


    }

    public String getValor(int fila, int columna) {

        if (items.length <= 0) {
            return "";
        }

        Object obj = items[fila].getCells()[columna].value;

        if (obj instanceof String) {
            return (String) obj;
        }

        return obj.toString();
    }

    public int getLineSelected() {
        return topLineIndex + lineSelected;
    }

    public int getSizeDatos() {
        return items.length;
    }

    public void clear() {
        if (items != null) {
            for (int i = 0; i < items.length; i++) {
                items[i] = null;
            }

            items = null;
        }
        scrollBar = null;
        gridInfo = null;
        itemORenderer = null;
    }

    private boolean outsideScreen(int columnSelected) {
        if(columnSelected < basecolumn) return true;
        int x = 0;
        for (int hi = basecolumn; hi <= columnSelected; hi++) {
            x = x + gridInfo.columnWidths[hi];
        }
        return x >  screenwidth;
    }
 
}// OGrid

